package com.wangsd.web.mircomerchant.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wangsd.web.mircomerchant.MicroSubmit;
import com.wangsd.web.mircomerchant.service.CertFicatesService;
import com.wangsd.web.mircomerchant.upload.service.impl.UploadServiceImpl;
import com.wangsd.web.mircomerchant.utils.MapSortUtil;
import com.wangsd.web.mircomerchant.utils.SSLContextUtils;
import com.wangsd.web.mircomerchant.utils.SignUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.util.*;

@Service
@Slf4j
public class CertFicatesServiceImpl implements CertFicatesService {
    @Override
    public JSONObject getCertFicates(String mchId,String apiSecret) {
        // 初始化一个HttpClient
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // Post请求
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/risk/getcertficates");
        /**
         * 这边需要您提供微信分配的商户号跟API密钥
         */
        Map<String, String> param = new HashMap<>(4);
        param.put("mch_id", mchId);
        param.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
        // 暂只支持HMAC-SHA256 加密
        param.put("sign_type", "HMAC-SHA256");
        // 对你的参数进行加密处理
        param.put("sign", SignUtil.wechatCertficatesSignBySHA256(param, apiSecret));
        httpPost.setEntity(new StringEntity(map2Xml(param), "UTF-8"));
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_XML.getMimeType());
        try {
            HttpResponse httpResponse = httpClient.execute(httpPost);
            log.info("获取平台证书响应 {}", httpResponse);
            if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) {
                String responseEntity = EntityUtils.toString(httpResponse.getEntity());
                //Document document = DocumentHelper.parseText(responseEntity);
                String s = MapSortUtil.xml2JSON(responseEntity);
                log.info("获取平台证书响应json串："+s);
                JSONObject responseObject = JSONObject.parseObject(s);
                Object xml = responseObject.get("xml");
                JSONObject resultObject = JSONObject.parseObject(JSON.toJSONString(xml));
                return resultObject;
            }
        } catch (Exception e) {
            log.error("执行httpclient请求平台证书序号错误 {}", e);
        }
        return null;
    }

    /**
     * 平台证书解密
     * @param associatedData
     * @param nonce
     * @param cipherText
     * @param apiv3Key
     * @return
     */
    @Override
    public String decryptCertSN(String associatedData, String nonce, String cipherText, String apiv3Key) throws Exception{
        final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(apiv3Key.getBytes(), "AES");
        GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, key, spec);
        cipher.updateAAD(associatedData.getBytes());
        return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
    }

    @Override
    @Transactional
    public JSONObject microSubmit(MicroSubmit microSubmit,String apiSecret,String certPath) {
        InputStream resourceAsStream = CertFicatesServiceImpl.class.getClassLoader().getResourceAsStream(certPath);
        SSLContext sslContextByStream = SSLContextUtils.getSSLContextByStream(resourceAsStream, microSubmit.getMch_id());
        // 初始化一个HttpClient
        CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContextByStream).build();
        // Post请求
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/applyment/micro/submit");

        /*包装数据*/
        Map<String, String> _param = packageParams(microSubmit,apiSecret);

        /*将参数的key进行排序*/
        Map<String, String> param = MapSortUtil.sortMapByKey(_param);
        httpPost.setEntity(new StringEntity(map2Xml(param), "UTF-8"));
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_XML.getMimeType());
        try {
            HttpResponse httpResponse = httpClient.execute(httpPost);
            log.info("获取申请入驻响应 {}", httpResponse);
            if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) {
                String responseEntity = EntityUtils.toString(httpResponse.getEntity());
                String s = MapSortUtil.xml2JSON(responseEntity);
                log.info("申请入驻响应 ："+s);
                JSONObject responseObject = JSONObject.parseObject(s);
                Object xml = responseObject.get("xml");
                JSONObject resultObject = JSONObject.parseObject(JSON.toJSONString(xml));
                return resultObject;
            }
        } catch (Exception e) {
            log.error("执行httpclient请求申请入驻错误 {}", e);
        }
        return null;
    }

    @Override
    public JSONObject microGetstate(String mch_id, String apiSecret, String certPath, String applyment_id) {
        InputStream resourceAsStream = CertFicatesServiceImpl.class.getClassLoader().getResourceAsStream(certPath);
        SSLContext sslContext = SSLContextUtils.getSSLContextByStream(resourceAsStream, mch_id);
        // 初始化一个HttpClient
        CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
        // Post请求
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/applyment/micro/getstate");

        /*包装数据*/
        Map<String, String> _param = new TreeMap<>();
        _param.put("version","1.0");
        _param.put("mch_id",mch_id);
        _param.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
        _param.put("sign_type","HMAC-SHA256");
        _param.put("applyment_id",applyment_id);
        _param.put("sign", SignUtil.wechatCertficatesSignBySHA256(_param, apiSecret));

        /*将参数的key进行排序*/
        Map<String, String> param = MapSortUtil.sortMapByKey(_param);
        httpPost.setEntity(new StringEntity(map2Xml(param), "UTF-8"));
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_XML.getMimeType());
        try {
            HttpResponse httpResponse = httpClient.execute(httpPost);
            log.info("获取查询申请状态响应 {}", httpResponse);
            if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) {
                String responseEntity = EntityUtils.toString(httpResponse.getEntity());
                String s = MapSortUtil.xml2JSON(responseEntity);
                log.info("查询申请状态响应 ："+s);
                JSONObject responseObject = JSONObject.parseObject(s);
                Object xml = responseObject.get("xml");
                JSONObject resultObject = JSONObject.parseObject(JSON.toJSONString(xml));
                return resultObject;
            }
        } catch (Exception e) {
            log.error("执行httpclient请求查询申请状态错误 {}", e);
        }
        return null;
    }


    private Map<String,String> packageParams(MicroSubmit microSubmit,String apiSecret){
        Map<String,String> params = new TreeMap<>();
        params.put("version", "3.0");
        params.put("cert_sn", microSubmit.getCert_sn());//需要接口获取
        params.put("mch_id", microSubmit.getMch_id());
        params.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
        params.put("sign_type","HMAC-SHA256");
        params.put("business_code",microSubmit.getBusiness_code());
        params.put("id_card_copy",microSubmit.getId_card_copy());//图片上传接口
        params.put("id_card_national",microSubmit.getId_card_national());//图片上传接口
        params.put("id_card_name",microSubmit.getId_card_name());//加密
        params.put("id_card_number",microSubmit.getId_card_number());//加密
        params.put("id_card_valid_time",microSubmit.getId_card_valid_time());
        params.put("account_name",microSubmit.getId_card_name());//加密
        params.put("account_bank",microSubmit.getAccount_bank());
        if (StringUtils.isNotBlank(microSubmit.getBank_name())) {
            params.put("bank_name", microSubmit.getBank_name());
        }
        params.put("bank_address_code",microSubmit.getBank_address_code());
        params.put("account_number",microSubmit.getAccount_number());//加密
        params.put("store_name",microSubmit.getStore_name());
        params.put("store_address_code",microSubmit.getStore_address_code());
        params.put("store_street",microSubmit.getStore_street());
        params.put("store_entrance_pic",microSubmit.getStore_entrance_pic());
        params.put("indoor_pic",microSubmit.getIndoor_pic());
        params.put("merchant_shortname",microSubmit.getMerchant_shortname());
        params.put("service_phone",microSubmit.getService_phone());
        params.put("product_desc",microSubmit.getProduct_desc());
        params.put("rate",microSubmit.getRate());
        params.put("contact",microSubmit.getId_card_name());//加密
        params.put("contact_phone",microSubmit.getContact_phone());//加密
        // 对你的参数进行加密处理
        params.put("sign", SignUtil.wechatCertficatesSignBySHA256(params, apiSecret));
        return params;
    }

    /**
     * map对象转xml
     *
     * @param map
     * @return
     */
    private String map2Xml(Map<String, String> map) {
        StringBuilder result = new StringBuilder();
        result.append("<xml>");
        if (map != null && map.keySet().size() > 0) {
            map.forEach((key, value) -> {
                result.append("<" + key + "><![CDATA[");
                result.append(value);
                result.append("]]></" + key + ">");
            });
        }
        result.append("</xml>");
        return result.toString();
    }
}
